package cn.maihe.elg.operation.service.guarantee;

import cn.maihe.elg.operation.config.ElgConfig;
import cn.maihe.elg.operation.exception.GuaranteeCheckRuntimeException;
import cn.maihe.elg.operation.model.bo.GuaranteeCheckBO;
import cn.maihe.elg.operation.model.bo.GuaranteeVerificationBO;
import cn.maihe.elg.operation.model.enums.*;
import cn.maihe.elg.operation.repository.entity.*;
import cn.maihe.elg.operation.repository.mapper.BidCustomerMapper;
import cn.maihe.elg.operation.service.BaseDaoService;
import cn.maihe.elg.operation.service.order.AcceptOrderInfoService;
import cn.maihe.elg.operation.service.order.GuaranteeAttachmentInfoService;
import cn.maihe.elg.operation.supports.guarantee.dto.FileCheckRespDTO;
import cn.maihe.elg.operation.supports.guarantee.dto.GuaranteeInfoReqDTO;
import cn.maihe.elg.operation.supports.guarantee.dto.GuaranteeInfoRespDTO;
import cn.maihe.elg.operation.supports.system.ElgResourceService;
import cn.maihe.framework.starter.base.sql.PageBo;
import cn.maihe.framework.starter.mybatis.dao.MybatisDaoImpl;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @Description 保函电子文件服务
 * @Author WJH
 * @Date 2021/03/25
 */
@Service
public class GuaranteeService extends BaseDaoService<GuaranteeDO> {

    @Autowired
    private BidCustomerMapper bidCustomerMapper;
    @Resource
    private ElgConfig elgConfig;
    @Resource
    private GuaranteeAttachmentInfoService guaranteeAttachmentInfoService;
    @Resource
    private ElgResourceService elgResourceService;
    @Resource
    private AcceptOrderInfoService acceptOrderInfoService;

    public PageBo<GuaranteeDO> selectPageBySql(int pageNo, int pageSize, String gmtCreateRange, GuaranteeVo vo) {
        Map<String, Object> paramsMap = toMapAndAddParams(vo);
        if (StringUtils.isNotBlank(gmtCreateRange)) {
            String[] rangeAy = gmtCreateRange.split(",");
            if (rangeAy.length > 1) {
                paramsMap.put("startGmtCreate", rangeAy[0] + " 00:00:00");
                paramsMap.put("endGmtCreate", rangeAy[1] + " 23:59:59");
            }
        }
        return this.selectPageBySql("selectGuaranteeList", "selectGuaranteeCount", paramsMap, pageNo, pageSize);
    }

    /**
     * 根据保函序列号&保函原文件 进行保函验真 文件md5一致
     *
     * @param centerId
     * @param orgId
     * @param serialNum
     */
    public GuaranteeVerificationBO guaranteeVerificationBySerialNum(long centerId, long orgId, String serialNum, Path guaranteePdf) {

        GuaranteeVerificationBO guaranteeVerificationBO = new GuaranteeVerificationBO();

        GuaranteeDO guaranteeDO = this.getGuarantee(centerId, orgId, null, serialNum);
        if (guaranteeDO == null) {
            throw new RuntimeException("查无此保函记录");
        }
        GuaranteeStatus status = GuaranteeStatus.resolve(guaranteeDO.getGuaranteeStatus());
        if (status != GuaranteeStatus.PROTECTING) {
            throw new RuntimeException("该保函非担保中保函.[" + status.getDesc() + "]");
        }
        try {
            String pdfMd5 = DigestUtils.md5DigestAsHex(Files.readAllBytes(guaranteePdf));
            String dbMd5 = guaranteeDO.getGuaranteeFileMd5();

            guaranteeVerificationBO.setSerialNum(guaranteeDO.getSerialNum());
            guaranteeVerificationBO.setSignName(guaranteeDO.getGuarantorName());
            guaranteeVerificationBO.setSignTime(DateFormatUtils.format(guaranteeDO.getServiceBeginTime(), "yyyy-MM-dd HH:mm:ss"));
            guaranteeVerificationBO.setIssuer(guaranteeDO.getGuarantorName());
            if (dbMd5 != null && dbMd5.equalsIgnoreCase(pdfMd5)) {
                guaranteeVerificationBO.setIsModified(2);
            } else {
                guaranteeVerificationBO.setIsModified(1);
            }
        } catch (IOException e) {
            throw new RuntimeException("保函验真异常:" + e.getMessage(), e);
        }
        return guaranteeVerificationBO;
    }

    /**
     * 保函查验
     */
    public GuaranteeCheckBO guaranteeCheckBySerialNum(long centerId, long orgId, String guaranteeNo, String serialNum) {
        GuaranteeDO guaranteeDO = getGuarantee(centerId, orgId, guaranteeNo, serialNum);
        if (guaranteeDO == null) {
            throw new RuntimeException("查无此保函记录");
        }

        GuaranteeType guaranteeType = GuaranteeType.resolve(guaranteeDO.getGuaranteeType());
        GuaranteeCategory guaranteeCategory = GuaranteeCategory.resolve(guaranteeDO.getGuaranteeCategory());
        GuaranteeCheckBO bo = new GuaranteeCheckBO();
        bo.setSerialNum(guaranteeDO.getSerialNum());
        bo.setGuaranteeNo(guaranteeDO.getGuaranteeNo());
        bo.setGuaranteeType(guaranteeType);
        bo.setGuaranteeCategory(guaranteeCategory);
        bo.setTenderer(guaranteeDO.getTenderer());
        bo.setBidCustomerName(guaranteeDO.getBidCustomerName());
        bo.setProposer(guaranteeDO.getBidCustomerName()); //申请人是否就是被保证人
        bo.setBidBond(guaranteeDO.getBidBond());
        bo.setProItem(null);//FIXME 后续处理
        bo.setIsAvert(null);//FIXME 明确后处理
        bo.setServiceBeginTime(guaranteeDO.getServiceBeginTime());
        bo.setServiceEndTime(guaranteeDO.getServiceEndTime());

        return bo;
    }

    public GuaranteeDO getGuarantee(long centerId, long orgId, String guaranteeNo, String serialNum) {
        if (StringUtils.isAllEmpty(guaranteeNo, serialNum)) {
            throw new RuntimeException("保函编号与保函序列号不能同时为空");
        }
        GuaranteeDOCondition condition = GuaranteeDOCondition.builder().andCenterIdEq(centerId).andOrgIdEq(orgId);
        if (StringUtils.isNoneBlank(guaranteeNo)) {
            condition.andGuaranteeNoEq(guaranteeNo);
        }
        if (StringUtils.isNotBlank(serialNum)) {
            condition.andSerialNumEq(serialNum);
        }
        return MybatisDaoImpl.run().selectOne(condition.build());
    }

    public GuaranteeInfoRespDTO guaranteeCheck(GuaranteeInfoReqDTO reqDTO) {
        if (StringUtils.isEmpty(reqDTO.getGuaranteeNo())) {
            throw new GuaranteeCheckRuntimeException("404", "保函编号不能为空");
        }
        if (StringUtils.isEmpty(reqDTO.getCreditCode())) {
            throw new GuaranteeCheckRuntimeException("404", "保函投标人信用统一码不能为空");
        }
        AcceptOrderInfoDO orderInfoDO = acceptOrderInfoService.getByGuaranteeNo(reqDTO.getGuaranteeNo());
        if (orderInfoDO == null) {
            throw new GuaranteeCheckRuntimeException("404", "查无此保函编号订单申请记录");
        }

        BidCustomerDOCondition bidCustomerDOCondition = BidCustomerDOCondition.builder()
                .andBidderCreditCodeEq(reqDTO.getCreditCode());
        List<BidCustomerDO> bidCustomerDOS = bidCustomerMapper.selectList(bidCustomerDOCondition.build());
        if (CollectionUtils.isEmpty(bidCustomerDOS)) {
            throw new GuaranteeCheckRuntimeException("405", "查无此投标人信用统一码");
        }
        GuaranteeDOCondition condition = GuaranteeDOCondition.builder().andGuaranteeNoEq(reqDTO.getGuaranteeNo());
        condition.andOrgIdIn(bidCustomerDOS.stream().map(BidCustomerDO::getOrgId).toArray(Object[]::new));
        GuaranteeDO guaranteeDO = MybatisDaoImpl.run().selectOne(condition.build());
        if (guaranteeDO == null) {
            throw new GuaranteeCheckRuntimeException("405", "查无此保函记录");
        }
        AcceptOrderStatus acceptOrderStatus = AcceptOrderStatus.resolve(orderInfoDO.getStatus());
        if (acceptOrderStatus != AcceptOrderStatus.HAS_OUT_GUARANTEE) {
            throw new GuaranteeCheckRuntimeException("405", "订单状态不是已出函:" + acceptOrderStatus.getDesc());
        }
        GuaranteeStatus guaranteeStatus = GuaranteeStatus.resolve(guaranteeDO.getGuaranteeStatus());
        if (guaranteeStatus != GuaranteeStatus.PROTECTING) {
            throw new GuaranteeCheckRuntimeException("405", "保函状态不是担保中:" + guaranteeStatus.getDesc());
        }


        GuaranteeType guaranteeType = GuaranteeType.resolve(guaranteeDO.getGuaranteeType());
        GuaranteeCategory guaranteeCategory = GuaranteeCategory.resolve(guaranteeDO.getGuaranteeCategory());
        GuaranteeInfoRespDTO bo = new GuaranteeInfoRespDTO();
        bo.setSerialNum(guaranteeDO.getSerialNum());
        bo.setGuaranteeNo(guaranteeDO.getGuaranteeNo());
        bo.setSectionNo(guaranteeDO.getSectionCode());
        bo.setSectionName(guaranteeDO.getSectionName());
        bo.setGuaranteeType(guaranteeType);
        bo.setGuaranteeCategory(guaranteeCategory);
        bo.setTenderer(guaranteeDO.getTenderer());
        bo.setBidCustomerName(guaranteeDO.getBidCustomerName());
        bo.setProposer(guaranteeDO.getBidCustomerName()); //申请人是否就是被保证人
        bo.setBidBond(guaranteeDO.getBidBond());
        bo.setProItem(null);//FIXME 后续处理
        bo.setIsAvert(null);//FIXME 明确后处理
        bo.setServiceBeginTime(guaranteeDO.getServiceBeginTime());
        bo.setServiceEndTime(guaranteeDO.getServiceEndTime());
        bo.setGuaranteeUrl(this.buildGuaranteeUrl(guaranteeDO.getAcceptOrderNo()));
        return bo;
    }

    private String buildGuaranteeUrl(String acceptOrderNo) {
        GuaranteeAttachmentInfoDO attachmentInfoDO = guaranteeAttachmentInfoService.getTypeAttachmentByAcceptOrderNo(acceptOrderNo, AttachmentFileType.TYPE_0);
        if (attachmentInfoDO != null) {
            try {
                String encodeRelativeUrl = elgResourceService.fmtNoAuthDownloadUrl(attachmentInfoDO.getFilePath());
                return encodeRelativeUrl;
            } catch (Exception e) {
                throw new RuntimeException("保函地址错误:" + e.getMessage(), e);
            }
        }
        return null;
    }

    public FileCheckRespDTO fileCheck(String md5, String guaranteeNo) {
        GuaranteeDOCondition condition = GuaranteeDOCondition.builder()
                .andGuaranteeNoEq(guaranteeNo);
        List<GuaranteeDO> guaranteeDOS = MybatisDaoImpl.run().selectList(condition.build());
        if (CollectionUtils.isEmpty(guaranteeDOS)) {
            throw new GuaranteeCheckRuntimeException("405", "查无此保函记录");
        }
        Optional<GuaranteeDO> guaranteeDOOptional = guaranteeDOS.stream().filter(item -> item.getGuaranteeFileMd5().equals(md5)).findFirst();
        FileCheckRespDTO respDTO = new FileCheckRespDTO();
        respDTO.setGuaranteeNo(guaranteeNo);
        if (guaranteeDOOptional.isPresent()) {
            GuaranteeDO guaranteeDO = guaranteeDOOptional.get();
            respDTO.setSerialNum(guaranteeDO.getSerialNum());
            respDTO.setIsModify(2);
        } else {
            respDTO.setIsModify(1);
        }
        return respDTO;
    }

    public GuaranteeDO getGuaranteeByAcceptOrderNo(String acceptOrderNo) {
        return this.selectOne(GuaranteeDOCondition.builder().andAcceptOrderNoEq(acceptOrderNo).build());
    }

    public GuaranteeDO getGuaranteeByGuaranteeNo(String guaranteeNo) {
        return this.selectOne(GuaranteeDOCondition.builder().andGuaranteeNoEq(guaranteeNo).build());
    }

    public GuaranteeDO getGuaranteeBySerialNum(String serialNum) {
        return this.selectOne(GuaranteeDOCondition.builder().andSerialNumEq(serialNum).build());
    }

    public void updateByAcceptOrderNo(GuaranteeDO updateGuarantee, String acceptOrderNo) {
        GuaranteeDOCondition condition = GuaranteeDOCondition.builder().andAcceptOrderNoEq(acceptOrderNo);
        this.update(updateGuarantee, condition.build());
    }
}
